/* * Copyright 2012 AppSatori s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package eu.appsatori.pipes; import java.util.ConcurrentModificationException; import com.google.appengine.api.NamespaceManager; import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceConfig; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.ImplicitTransactionManagementPolicy; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.KeyFactory; import com.google.appengine.api.datastore.ReadPolicy; import com.google.appengine.api.datastore.Transaction; import com.google.appengine.api.datastore.TransactionOptions; /** * Internal helper class to run operations in transactions and the right namespace. * * @author <a href="mailto:vladimir.orany@appsatori.eu">Vladimir Orany</a> * */ class DatastoreHelper { static interface Operation<V>{ V run(DatastoreService ds); } private static final int RETRIES = 10; private static final String FLOW_NAMESPACE = "eu_appsatori_pipes"; static final String TASK_KIND = "task"; static final String SUBTASK_KIND = "subtask"; private DatastoreHelper() {} static <V> V call(Operation<V> op, V defaultValue){ return call(op, defaultValue, TransactionOptions.Builder.withDefaults()); } static <V> V call(Operation<V> op, V defaultValue, TransactionOptions txops){ int attempt = 1; while(attempt <= RETRIES){ String oldNs = NamespaceManager.get(); NamespaceManager.set(FLOW_NAMESPACE); DatastoreServiceConfig config = DatastoreServiceConfig.Builder.withImplicitTransactionManagementPolicy(ImplicitTransactionManagementPolicy.AUTO).readPolicy(new ReadPolicy(ReadPolicy.Consistency.STRONG)); DatastoreService ds = DatastoreServiceFactory.getDatastoreService(config); Transaction tx = ds.beginTransaction(); try { V result = op.run(ds); tx.commit(); return result; } catch (ConcurrentModificationException e){ attempt++; } finally { if(tx.isActive()){ tx.rollback(); } NamespaceManager.set(oldNs); } } return defaultValue; } static Key getKey(String taskId) { return KeyFactory.createKey(TASK_KIND, taskId); } static Key getKey(String taskId, int index) { return KeyFactory.createKey(getKey(taskId), SUBTASK_KIND, index + 1); } }